package gov.pbc.nn.uflo;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import com.bstek.bdf2.core.context.ContextHolder;
import com.bstek.bdf2.core.orm.hibernate.ISessionCallback;
import com.bstek.uflo.client.service.ProcessClient;
import com.bstek.uflo.model.HistoryProcessInstance;
import com.bstek.uflo.model.ProcessInstance;
import com.bstek.uflo.model.ProcessInstanceState;
import com.bstek.uflo.query.HistoryProcessInstanceQuery;
import com.bstek.uflo.query.ProcessInstanceQuery;
import com.bstek.uflo.service.HistoryService;
import com.bstek.uflo.service.ProcessService;

import gov.pbc.nn.core.dao.PbcnnCoreHibernateDao;
import gov.pbc.nn.core.dao.PbcnnCoreJdbcDao;
import gov.pbc.nn.core.utils.MapUtils;
import gov.pbc.nn.uflo.entity.Opinion;

public class UfloUtils {

	/**
	 * 查询审核意见
	 * 
	 * @param processInstanceId
	 *            流程实例ID，可选。
	 * @param businessId
	 *            业务ID，必须。
	 * @param nodeName
	 *            节点名称，可选，如果为空则查询所有节点的意见
	 * @param taskId
	 *            任务Id，可选，如果为空则查询所有任务的意见
	 * @param users
	 *            审核人，可选，如果为空则查询所有人的意见
	 * @return
	 */
	public static List<Opinion> getOpinions(Long processInstanceId,
			String businessId,String nodeName, Long taskId, List<String> users) {
		PbcnnCoreHibernateDao dao = ContextHolder
				.getBean(PbcnnCoreHibernateDao.BEAN_ID);
		DetachedCriteria dc = DetachedCriteria.forClass(Opinion.class);
		dc.add(Restrictions.eq("busKey", businessId));
		dc.add(Restrictions.eq("invalid", false));
		if (processInstanceId != null) {
			dc.add(Restrictions.eq("processInstanceId", processInstanceId));
		}
		if (StringUtils.isNotEmpty(nodeName)) {
			dc.add(Restrictions.eq("nodeName", nodeName));
		}
		if (taskId!=null) {
			dc.add(Restrictions.eq("taskId", taskId));
		}
		if (users != null && users.size() > 0) {
			dc.add(Restrictions.in("username", users));
		}
		dc.addOrder(Order.desc("createDate"));
		return (List<Opinion>) dao.query(dc);
	}

	/**
	 * 查询最新审核意见
	 * 
	 * @param processInstanceId
	 *            流程实例ID，可选。
	 * @param businessId
	 *            业务ID，必须。
	 * @param nodeName
	 *            节点名称，可选，如果为空则查询所有节点的意见
	 * @param taskId
	 *            任务Id，可选，如果为空则查询所有任务的意见
	 * @param users
	 *            审核人，可选，如果为空则查询所有人的意见
	 * @return
	 */
	public static List<Opinion> getLatestOpinions(Long processInstanceId,
			String businessId, String nodeName,Long taskId, List<String> users) {
		PbcnnCoreHibernateDao dao = ContextHolder
				.getBean(PbcnnCoreHibernateDao.BEAN_ID);
		String sql = "SELECT\n"
				+ "	a.*\n"
				+ "FROM\n"
				+ "	t_uflo_opinion a\n"
				+ "INNER JOIN (\n"
				+ "	SELECT\n"
				+ "		USERNAME_,\n"
				+ "		MAX(CREATE_DATE_) as CREATE_DATE_\n"
				+ "	FROM\n"
				+ "		t_uflo_opinion\n"
				+ "		where INVALID_=0\n"
				+ "	GROUP BY\n"
				+ "		USERNAME_\n"
				+ ") b ON a.USERNAME_ = b.USERNAME_ and a.CREATE_DATE_=b.CREATE_DATE_\n"
				+ "WHERE\n" + "	a.INVALID_=0 AND a.BUS_KEY_ = :busKey";
		final Map<String, Object> params = new HashMap<String, Object>();
		params.put("busKey", businessId);

		if (processInstanceId != null) {
			sql += " and PROCESS_INSTANCE_ID_=:processInstanceId";
			params.put("processInstanceId", processInstanceId);
		}
		if (StringUtils.isNotEmpty(nodeName)) {
			sql += " and NODE_NAME_=:nodeName";
			params.put("nodeName", nodeName);
		}
		if (taskId!=null) {
			sql += " and TASK_ID_=:taskId";
			params.put("taskId", taskId);
		}
		if (users != null && users.size() > 0) {
			sql += " and b.USERNAME_ in :users";
			params.put("users", users);
		}
		sql += " order by CREATE_DATE_ DESC";
		final String sqlStr = sql;
		return dao.doInHibernateSession(new ISessionCallback<List<Opinion>>(){

			@Override
			public List<Opinion> doInSession(Session session) {
				return session.createSQLQuery(sqlStr)
						.addEntity("a", Opinion.class).setProperties(params).list();
			}
			
		});
	}

	/**
	 * 根据业务ID获取顶层流程的状态
	 * @param businessId
	 * @return
	 */
	public static ProcessState getProcessState(String businessId){
		ProcessClient pc = ContextHolder.getBean(ProcessClient.BEAN_ID);
		List<ProcessInstance> list = getProcessInstance(businessId);
		if(list.isEmpty()){
			List<HistoryProcessInstance> hisList = getHistoryProcessInstance(businessId);
			if(hisList.isEmpty()){
				return ProcessState.NONE;
			}else{
				return ProcessState.OVER;
			}
		}else{
			for(ProcessInstance pi:list){
				long pId = pi.getParentId();
				if(pId>0){
					ProcessInstance pPi = null;
					while(pId>0){
						pPi = pc.getProcessInstanceById(pId);
						pId = pPi.getParentId();
					}
					return pPi.getState()==ProcessInstanceState.End ?ProcessState.OVER:ProcessState.RUNNING;
				}else{
					return pi.getState()==ProcessInstanceState.End ?ProcessState.OVER:ProcessState.RUNNING;
				}
			}
		}
		return ProcessState.NONE;
	}
	
	/**
	 * 根据业务ID判断该业务在顶层流程中是否正处于运行中
	 * 
	 * @param businessId
	 * @return
	 */
	public static boolean isInProcessInstance(String businessId) {
		ProcessState ps = getProcessState(businessId);
		return ps==ProcessState.RUNNING;
	}

	/**
	 * 根据业务ID判断该业务在顶层流程中是否正已结束
	 * 
	 * @param businessId
	 * @return
	 */
	public static boolean hasHistoryProcessInstance(String businessId) {
		ProcessState ps = getProcessState(businessId);
		return ps==ProcessState.OVER;
	}
	
	/**
	 * 根据业务主键删除流程实例，同时会删除任务和审批历史记录
	 * @param businessId 业务主键ID
	 * @param deleteProcessOpinion 是否删除审批过程及审核意见 
	 */
	public static void deleteProcessInstance(String businessId,boolean deleteProcessOpinion) {
		if (StringUtils.isNotEmpty(businessId)) {
			ProcessService processService = ContextHolder.getBean(ProcessService.BEAN_ID);
			ProcessInstanceQuery processInstanceQuery = processService.createProcessInstanceQuery();
			List<ProcessInstance> processInstanceList = processInstanceQuery.businessId(businessId).list();
			if (null != processInstanceList && processInstanceList.size() > 0) {
				long rootProcessInstanceId = 0;
				for (ProcessInstance processInstance : processInstanceList) {
					long parentId = processInstance.getParentId();
					if (parentId == 0) {
						rootProcessInstanceId = processInstance.getId();
					}
				}
				processService.deleteProcessInstanceById(rootProcessInstanceId);
			}

			PbcnnCoreHibernateDao hDao = ContextHolder.getBean(PbcnnCoreHibernateDao.BEAN_ID);
//			PbcnnCoreJdbcDao jDao = ContextHolder.getBean(PbcnnCoreJdbcDao.BEAN_ID);
//			String sql = "delete from UFLO_VARIABLE where PROCESS_INSTANCE_ID_ in (select p.ID_ from uflo_process_instance p where p.BUSINESS_ID_=?)";
//			jDao.getJdbcTemplate().update(sql, businessId);
//			sql = "delete from uflo_his_variable where HIS_PROCESS_INSTANCE_ID_ in (select p.ID_ from uflo_his_process_instance p where p.BUSINESS_ID_=?)";
//			jDao.getJdbcTemplate().update(sql, businessId);
//			sql = "delete from uflo_process_instance where BUSINESS_ID_=?";
//			jDao.getJdbcTemplate().update(sql, businessId);
//			sql = "delete from uflo_his_process_instance where BUSINESS_ID_=?";
//			jDao.getJdbcTemplate().update(sql, businessId);
//
//			sql = "delete from uflo_task_participator where TASK_ID_ in (select ID_ from uflo_task where BUSINESS_ID_=?)";
//			jDao.getJdbcTemplate().update(sql, businessId);
//			sql = "delete from uflo_task where BUSINESS_ID_=?";
//			jDao.getJdbcTemplate().update(sql, businessId);
//			sql = "delete from uflo_his_task where BUSINESS_ID_=?";
//			jDao.getJdbcTemplate().update(sql, businessId);
			if(deleteProcessOpinion){
				String hql = "delete " + Opinion.class.getName() + " where busKey=:busKey";
				hDao.executeUpdate(hql, MapUtils.newHashMap(new String[] { "busKey" }, new Object[] { businessId }));
			}
		}
	}
	
	/**
	 * 根据业务主键获取运行中的流程实例
	 * @param businessId
	 * @return
	 */
	public static List<ProcessInstance> getProcessInstance(String businessId){
		if(StringUtils.isEmpty(businessId)){
			return Collections.EMPTY_LIST;
		}
		ProcessClient pc = ContextHolder.getBean(ProcessClient.BEAN_ID);
		ProcessInstanceQuery piq = pc.createProcessInstanceQuery();
		piq.businessId(businessId);
		return piq.list();
	}
	
	/**
	 * 根据业务主键获取历史流程实例
	 * @param businessId
	 * @return
	 */
	public static List<HistoryProcessInstance> getHistoryProcessInstance(String businessId){
		if(StringUtils.isEmpty(businessId)){
			return Collections.EMPTY_LIST;
		}
		HistoryService hs = ContextHolder.getBean(HistoryService.BEAN_ID);
		HistoryProcessInstanceQuery hpiq = hs.createHistoryProcessInstanceQuery();
		hpiq.businessId(businessId);
		return hpiq.list();
	}
	
	public static enum ProcessState {
		/**
		 * 运行中
		 */
		RUNNING,
		/**
		 * 结束
		 */
		OVER,
		/**
		 * 无流程实例，即未开启流程
		 */
		NONE;
	}
}
